package yangbajing.util.web

import scala.xml.{Elem, Text, NodeSeq}

import net.liftweb.common.Box

import net.liftweb.util.Helpers._
import net.liftweb.http.js.{JsCmd, JsMember, JsExp}
import net.liftweb.http.js.jquery.JqJE
import net.liftweb.http.js.JsCmds.HasTime

trait jQueryBase {
  def jq: JsExp

  protected val _jsExps = collection.mutable.ListBuffer.empty[JsMember]

  def cmd: JsCmd = _jsExps.foldLeft[JsExp](jq)(_ ~> _).cmd

  import jQueryBase._

  def removeDisabled(): this.type =
    removeAttr("disabled")

  def disabled(): this.type =
    attr("disabled", "disabled")

  def show(): this.type = show(None)

  def show(time: Option[TimeSpan]): this.type = {
    _jsExps += JqShow(time)
    this
  }

  def hide(): this.type = hide(None)

  def hide(time: Option[TimeSpan]): this.type = {
    _jsExps += JqHide(time)
    this
  }

  def html(elems: Seq[Elem]): this.type = {
    _jsExps += JqJE.JqHtml(NodeSeq.fromSeq(elems))
    this
  }

  def html(content: NodeSeq): this.type = {
    _jsExps += JqJE.JqHtml(content)
    this
  }

  def html(content: String): this.type =
    html(if (content == "") NodeSeq.Empty else Text(content))

  def html[T <: AnyVal](content: T): this.type =
    html(Text(content.toString))

  def html(): this.type = {
    _jsExps += JqJE.JqHtml()
    this
  }

  def append(content: NodeSeq): this.type = {
    _jsExps += JqJE.JqAppend(content)
    this
  }

  def append(value: String): this.type =
    append(Text(value))

  def appendTo(content: NodeSeq): this.type = {
    _jsExps += JqJE.JqAppendTo(content)
    this
  }

  def prepared(content: NodeSeq): this.type = {
    _jsExps += JqJE.JqPrepend(content)
    this
  }

  def preparedTo(content: NodeSeq): this.type = {
    _jsExps += JqJE.JqPrependTo(content)
    this
  }

  def value(v: String): this.type = {
    _jsExps += SetValue(v)
    this
  }

  def value(v: JsExp): this.type = {
    _jsExps += SetValue(v)
    this
  }

  def `val`(v: String): this.type =
    value(v)

  def `val`(v: JsExp): this.type =
    value(v)

  def `val`(): this.type =
    value()

  def value(): this.type = {
    _jsExps += Value()
    this
  }

  def attr(key: String): this.type = {
    _jsExps += JqJE.JqGetAttr(key)
    this
  }

  def attr(key: String, value: JsExp): this.type = {
    _jsExps += JqJE.JqAttr(key, value)
    this
  }

  def removeAttr(key: String): this.type = {
    _jsExps += RemoveAttr(key)
    this
  }

  def getClass(key: String): this.type = {
    _jsExps += JqJE.JqGetAttr(key)
    this
  }

  def setClass(value: JsExp): this.type = {
    attr("class", value)
    this
  }

  def remove(): this.type = {
    _jsExps += JqJE.JqRemove()
    this
  }

  def removeClass(value: String): this.type = {
    _jsExps += JqRemoveClass(value)
    this
  }

  def addClass(value: String): this.type = {
    _jsExps += JqAddClass(value)
    this
  }

  def replaceWith(content: NodeSeq): this.type = {
    _jsExps += JqJE.JqReplace(content)
    this
  }
}

object jQueryBase {

  private case class RemoveAttr(key: String) extends JsExp with JsMember {
    def toJsCmd = "removeAttr(" + key.encJs + ")"
  }

  private case class SetValue(value: JsExp) extends JsExp with JsMember {
    def toJsCmd = "val(" + value.toJsCmd + ")"
  }

  private case class Value() extends JsExp with JsMember {
    def toJsCmd = "val()"
  }

  private case class JqRemoveClass(value: String) extends JsExp with JsMember {
    def toJsCmd = "removeClass(" + value.encJs + ")"
  }

  private case class JqAddClass(value: String) extends JsExp with JsMember {
    def toJsCmd = "addClass(" + value.encJs + ")"
  }

  private case class JqShow(time: Box[TimeSpan]) extends JsExp with JsMember with HasTime {
    def toJsCmd = "show(" + timeStr + ")"
  }

  private case class JqHide(time: Box[TimeSpan]) extends JsExp with JsMember with HasTime {
    def toJsCmd = "hide(" + timeStr + ")"
  }

}
